let configuration = require('../../configuration');
let utils = require('../../utils');
let async = require('async');
let handCardService = require('../inner-event-services/handCardService');

class Pile {
    constructor(type, side) {
        this.type = type;
        this.side = side;

        this.topCard = null;
        this.cardCount = 0;

        this.width = configuration.get('components.card.thumb.width');
        this.height = configuration.get('components.card.thumb.height');
        this.__calculateX();
        this.__calculateY();
        this.__load();

        this.contentCards = null;
    }

    init(initConfig) {
        this.game = initConfig.game;
        this.compId = initConfig.id;
        this.componentContainer = initConfig.componentContainer;
    }

    __load() {
        configuration.getImage('back', image => {
            this.back = image;
        });
    }

    __calculateX() {
        let leftSideBarWidth = configuration.get('components.leftSideBar.width');
        let hMargin = configuration.get('components.slot.hMargin');
        let leftSideBarMarginRight = configuration.get('components.leftSideBar.marginRight');
        let slotA = this.width > this.height ? this.width : this.height;
        if (this.type == 'deck' || this.type == 'grave' || this.type == 'out') {
            if (this.side == 'bottom') {
                this.x = leftSideBarWidth + leftSideBarMarginRight + this.width + (hMargin + slotA) * 5 + hMargin + this.width / 2;
            } else {
                this.x = leftSideBarWidth + leftSideBarMarginRight + this.width / 2;
            }
        } else if (this.type == 'ex') {
            if (this.side == 'bottom') {
                this.x = leftSideBarWidth + leftSideBarMarginRight + this.width / 2;
            } else {
                this.x = leftSideBarWidth + leftSideBarMarginRight + this.width + (hMargin + slotA) * 5 + hMargin + this.width / 2;
            }
        } else throw new Error();
    }

    __calculateY() {
        let vMargin = configuration.get('components.slot.vMargin');
        let windowHeight = configuration.get('window.height');
        if (this.type == 'grave') {
            if (this.side == 'bottom') {
                this.y = windowHeight - (this.height + vMargin) * (2 + 1) - vMargin + this.height / 2;
            } else {
                this.y = (this.height + vMargin) * (2) + vMargin + this.height / 2;
            }
        } else if (this.type == 'out' || this.type == 'ex') {
            if (this.side == 'bottom') {
                this.y = windowHeight - (this.height + vMargin) * (1 + 1) - vMargin + this.height / 2;
            } else {
                this.y = (this.height + vMargin) * (1) + vMargin + this.height / 2;
            }
        } else if (this.type == 'deck') {
            if (this.side == 'bottom') {
                this.y = windowHeight - (this.height + vMargin) - vMargin + this.height / 2;
            } else {
                this.y = vMargin + this.height / 2;
            }
        } else throw new Error();
    }

    mouseDown() {
        if (this.contentCards == null) {
            // show the pile
            this.game.broadcast('showPile', this);
        } else {
            let self = this;
            async.each(this.contentCards, function (c, next) {
                c.onCardAnimation(self, {
                    compId: c.compId, operation: 'move', x: self.x, y: self.y, cb: function () {
                        next();
                    }
                });
            }, () => {
                this.contentCards.forEach(c => {
                    this.componentContainer.setOutstandRect(null);
                    this.componentContainer.removeComponent(c);
                });
                this.contentCards = null;
            });
        }
    }

    draw(canvas) {
        if (this.contentCards) {
            this.__drawCards(canvas);
        } else {
            this.__drawPile(canvas);
        }
    }

    __drawPile(canvas) {
        if (this.cardCount === 0) return; // draw nothing if it's empty
        let ctx = canvas.getContext('2d');
        let drawTimes = this.cardCount / configuration.get('components.pile.drawEvery');
        let dx = configuration.get('components.pile.dx');
        let dy = configuration.get('components.pile.dy');
        if (this.side == 'bottom') {
            if (this.type == 'ex') {
                dx *= -1;
            }
        } else {
            dy *= -1;
            if (this.type == 'deck' || this.type == 'out' || this.type == 'grave') {
                dx *= -1;
            }
        }
        let x = this.x - this.width / 2;
        let y = this.y - this.height / 2;
        for (let i = 0; i < drawTimes; ++i) {
            x += i * dx;
            y += i * dy;
            if (this.back) {
                ctx.drawImage(this.back, x, y, this.width, this.height);
            } else {
                ctx.strokeStyle = 'black';
                ctx.strokeRect(x, y, this.width, this.height);
            }
        }
        if (this.type == 'deck' || this.type == 'ex') {
            if (this.back) {
                ctx.drawImage(this.back, x, y, this.width, this.height);
            }
        } else {
            if (this.topCard) {
                let topCard = this.topCard;
                if (topCard.front) {
                    ctx.drawImage(topCard.front, x, y, this.width, this.height);
                }
            }
        }
        // draw the pile card size
        ctx.textBaseline = 'middle';
        ctx.textAlign = 'center';
        ctx.fillStyle = 'yellow';
        ctx.font = '40px Helvetica Helvetica';
        utils.drawTextWithShadow(ctx, '' + this.cardCount, this.x, this.y + this.height / 2);
    }

    __drawCards(canvas) {
        // cards are added as components
        // just draw the pile it self
        let ctx = canvas.getContext('2d');
        if (this.back) {
            ctx.save();
            ctx.globalAlpha = 0.5;
            ctx.drawImage(this.back, this.x - this.width / 2, this.y - this.height / 2, this.width, this.height);
            ctx.restore();
        }
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.font = '50px Helvetica Helvetica';
        ctx.fillStyle = 'white';
        ctx.fillText(configuration.get('i18n.packUpPile'), this.x, this.y);
    }

    onRequirePile(sender, params) {
        let type = params.type;
        let side = params.side;
        let cb = params.cb;
        if (this.type == type && this.side == side) {
            cb(this);
        }
    }

    showContentCards(cards) {
        this.contentCards = cards;
        cards.forEach(c => {
            c.direction[0] = 'up';
            c.direction[1] = 0;
            c.x = this.x;
            c.y = this.y;
            c.mode = 'inPile';
            this.componentContainer.addComponent(c);
            this.componentContainer.outstand(c);
        });
        let leftSideBarWidth = configuration.get('components.leftSideBar.width');
        let windowWidth = configuration.get('window.width');
        let windowHeight = configuration.get('window.height');
        this.componentContainer.setOutstandRect(leftSideBarWidth, 0, windowWidth - leftSideBarWidth, windowHeight);
        // calculate the card position
        let hMargin = configuration.get('components.slot.hMargin');
        let vMargin = configuration.get('components.slot.vMargin');
        let startX = leftSideBarWidth + hMargin + this.width / 2;
        let startY = vMargin + this.height / 2;
        let endX = windowWidth - hMargin - this.width / 2;
        let currentX = startX;
        let currentY = startY;

        cards.forEach(c => {
            c.onCardAnimation(this, {compId: c.compId, operation: 'move', x: currentX, y: currentY});
            while (true) {
                currentX += hMargin + this.width;
                if (currentX > endX) {
                    currentX = startX;
                    currentY += vMargin + this.height;
                }
                if (currentX > this.x - this.width && currentX < this.x + this.width &&
                    currentY > this.y - this.height && currentY < this.y + this.height) {
                    // would cover the pile itself
                    continue;
                }
                break;
            }
        });
    }

    onPileCardMove(sender, args) {
        if (this.type === args.from) {
            let self = this;
            let side = args.side;
            if (this.side === side) {
                let cards = args.cards;
                for (let i = cards.length - 1; i >= 0; --i) {
                    let card = cards[i];
                    card.x = this.x;
                    card.y = this.y;
                    card.direction = ['up', 0];
                    this.componentContainer.addComponent(card);
                }
                if (args.to === 'hand') {
                    this.cardCount -= cards.length;
                    handCardService.addCard(side, cards);
                } else {
                    let pile = args.to;
                    this.game.componentBroadcast('requirePile', this, {
                        type: pile,
                        side: side,
                        cb: function (pile) {
                            let i = -1;
                            let finishCount = 0;
                            async.eachSeries(cards, function (card, next) {
                                card.mode = 'animation';
                                ++i;
                                setTimeout(function () {
                                    self.cardCount -= 1;
                                    card.onCardAnimation(self, {
                                        compId: card.compId,
                                        operation: 'move',
                                        x: pile.x, y: pile.y,
                                        period: 0.2 * 1000,
                                        cb: function () {
                                            pile.cardCount += 1;
                                            ++finishCount;
                                            card.mode = 'hide';
                                            pile.topCard = card;
                                        }
                                    });
                                }, 50 * i);
                                next();
                            }, function () {
                                if (args.fromTop) {
                                    self.topCard = args.fromTop;
                                }
                                if (args.toTop) {
                                    pile.topCard = args.toTop;
                                }
                                let interval = setInterval(function () {
                                    if (finishCount == cards.length) {
                                        for (let card of cards) {
                                            self.componentContainer.removeComponent(card);
                                        }
                                        clearInterval(interval);
                                    }
                                }, 50);
                            });
                        }
                    });
                }
            }
        }
    }
}

module.exports = Pile;
